<?php

class Mysql
{
	public $db;
	public $stmt;
	public $error;
	public $log;

	private static $instance;

	public static function singleton()
	{
		if (!isset(self::$instance))
		{
			$class = __CLASS__;
			self::$instance=new $class;
		}

		return self::$instance;
	}

	public function __clone() 
	{
		trigger_error('Cloning not allowed.', E_USER_ERROR); 
	}

	public function __construct()
	{
		try
		{
			@$this->db=new mysqli(DBHOST, DBUSER, DBPASS, DBBASENAME);

			if (mysqli_connect_error())
			{
				throw new Exception('Database error:' . mysqli_connect_error());
			}
		}
		catch( Exception $e )
		{
			print $e->getMessage();
		}

		$this->db->set_charset('utf8');
	}

	function __destruct()
	{
		$this->db->close();
		
		if ( is_object( $this->stmt ) ) {
		
			$this->stmt->close();	
			
		}

		if ( DEBUGDB )
		{
			$this->db_log($this->log);
		}
	}

	function __call($func, $arg_array)
	{
		switch ($func)
		{
			case 'num_rows':
				if ($arg_array != NULL)
				{
					$this->execute_query($arg_array);
					$num_rows=$this->execute_result_info();

					return $num_rows['num_rows'];
				}

				$result=$this->execute_num_rows();
				return $result;
				break;
			case 'insert_id':
				if ($arg_array != NULL)
				{
					$this->execute_query($arg_array);
					$num_rows=$this->execute_result_info();

					return $num_rows['insert_id'];
				}

				$result=$this->execute_num_rows();
				return $result;
				break;
			case 'query':
				$this->execute_query($arg_array);

				$result=$this->execute_result_array();
				return $result;
				break;
		}
	}

	function __get($v)
	{
		$num_rows=$this->execute_result_info();
		return $num_rows[$v];
	}

	private function execute_query($arg_array = NULL)
	{
		//determine the types of arguments

		$sql_query=array_shift($arg_array); // the first element is returned to sql_query and then removed

		foreach ($arg_array as $v)
		{
			switch ($v)
			{
				case is_string($v):
					$types.='s';

					break;

				case is_int($v):
					$types.='i';

					break;

				case is_double($v):
					$types.='d';

					break;
			}
		}

		// prepare the query
		print mysqli_connect_error();
		$this->stmt=$this->db->prepare($sql_query);

		// binding parameters if has any
		try
		{
			if (isset($arg_array[0]))
			{
				array_unshift($arg_array, $types);
				$bind=@call_user_func_array(array
				(
				$this->stmt,
				'bind_param'
				),                      $arg_array);
			}

			if ($bind)
			{
				$time_start=microtime(true);
				$this->stmt->execute();
				$this->stmt->store_result();
				$time_end=microtime(true);
				$time    =$time_end - $time_start;

				$this->log[]=array
				(
				"query" => $sql_query,
				"time"  => $time
				);
			}
			else
			{
				throw new Exception('Binding error:' . $this->db->error);
			}
		}
		catch( Exception $e )
		{
			print $e->getMessage();
		}
	}

	private function execute_result_info()
	{
		if ($this->stmt->affected_rows > 0)
		{
			$num_rows=$this->stmt->affected_rows;
		}
		else
		{
			$num_rows=$this->stmt->num_rows();
		}

		$result['num_rows'] =$num_rows;
		$result['insert_id']=$this->stmt->insert_id;

		return $result;
	}

	private function execute_result_array()
	{
		try
		{
			if ($this->stmt->error)
			{
				throw new Exception('MySQLi STMT error:' . $this->stmt->error);
			}

			$result_metadata=@$this->stmt->result_metadata();
		}
		catch( Exception $e )
		{
			print $e->getMessage();
		}

		if (is_object($result_metadata))
		{
			$result_fields=array();

			while ($field=$result_metadata->fetch_field())
			{
				array_unshift($result_fields, $field->name);
				$params[]=&$row[$field->name];
			}

			call_user_func_array(array
			(
			$this->stmt,
			'bind_result'
			),               $params);

			while ($this->stmt->fetch())
			{
				foreach ($row as $key => $val)
				{
					$c[$key]=$val;
				}

				$result[]=$c;
			}

			return $result;
		}
		elseif ($this->stmt->errno == 0)
		{
			return true;
		}
		else
		{
			return $this->stmt->errno;
		}
	}

	/*here is the function for logging*/
	function db_log($query_arr)
	{
		$fh=fopen(DBLOGFILE, 'a') or die("can't open the log file");
		$i =0;

		foreach ($query_arr as $k => $q)
		{
			$sql = $sql . "<query_" . $i . "><sql><![CDATA[ " . $q['query'] . "]]></sql><time>" . $q['time']
			. "</time></query_" . $i . ">\n";

			$i++;
		}

		$xml.="<pagewiev>\n";
		$xml.="<date><![CDATA[ " . date("F j, Y, g:i a") . "]]></date>\n";
		$xml.="<ip><![CDATA[ " . $_SERVER['REMOTE_ADDR'] . "]]></ip>\n";
		$xml.="<browser><![CDATA[ " . $_SERVER['HTTP_USER_AGENT'] . "]]></browser>\n";
		$xml.="<url><![CDATA[ " . $_SERVER['REQUEST_URI'] . "]]></url>\n";
		$xml.="<ref><![CDATA[ " . $_SERVER['HTTP_REFERER'] . "]]></ref>\n";
		$xml.="<memory><![CDATA[ " . memory_get_peak_usage() . "]]></memory>\n";
		$xml.="<sql>" . $sql . "</sql>";
		$xml.="</pagewiev>\n";

		fwrite($fh, $xml);
		fclose($fh);
	}
}
?>